"""
@author: xiangping
@contact: xiangpingbu@gmail.com
@time: 2019/12/28 6:01 下午
@file: convert.py
@Desc: 封装数据库操作
"""
from app.exts import db
from datetime import datetime

#
# def query(table, *criterion, **params):
#     """
#     查询单条或者多条数据
#     :param table:  数据库表映射对象
#     :param criterion:   查询条件
#     :return:  查询得到的一条或者多条数据
#     """
#     if criterion is not None:
#         if len(criterion) > 0 and criterion[0] is None:
#             criterion = tuple()
#
#     order_by_flag = False
#     if params.get('order_by') is not None:
#         order_by_flag = True
#         order_by_content = params["order_by"]
#     if "order_by" in params: del params["order_by"]
#
#     # == 函数被重载
#     condition = list(map(lambda x: table.__dict__[x] == params[x], params))
#     condition.extend(criterion)
#     result = table.query.filter(*condition)
#
#     if order_by_flag:
#         result = result.order_by(order_by_content)
#     return result


def add_one(model):
    """
    插入一条或者多条数据
    :param tables: 数据库表映射对象
    :return: 插入的一条或者多条数据的主键,以list形式返回
    """
    db.session.add(model)
    db.session.flush()
    db.session.refresh(model)
    return model


def add_all(instances):
    """
    插入一条或者多条数据
    :param tables: 数据库表映射对象
    :return: 插入的一条或者多条数据的主键,以list形式返回
    """
    db.session.add_all(instances)
    db.session.flush()
    for instance in instances:
        db.session.refresh(instance)

    return instances


def delete_from(table, *criterion):
    """
    删除一条或者多条数据
    :param tables: 数据库表映射对象
    :return: 插入的一条或者多条数据的主键,以list形式返回
    """
    if criterion is not None:
        if len(criterion) > 0 and criterion[0] is None:
            criterion = tuple()
    condition = []
    condition.extend(criterion)
    table.query.filter(*condition).delete()
    return table


def query(table, *criterion, **params):
    """

    查询单条或者多条数据
    :param table:  数据库表映射对象
    :param criterion:   查询条件
    :param params: 特殊操作及条件
    :return:  查询得到的一条或者多条数据
    用法
        ret = convert.base_query(ShaoJiePredictPO,
                             ShaoJiePredictPO.DateTime.between(start, end),
                             order_by=ShaoJiePredictPO.DateTime.asc(),
                             limit=limit,
                             page=1,
                             per_page=15)
    """
    if criterion is not None:
        if len(criterion) > 0 and criterion[0] is None:
            criterion = tuple()

    ops = ['order_by', 'limit', 'page', 'per_page']
    ops_dict = {}
    for op in ops:
        if op in params.keys():
            if params[op] is not None:
                ops_dict[op] = params[op]
            del params[op]

    # == 函数被重载
    condition = list(map(lambda x: table.__dict__[x] == params[x], params))
    condition.extend(criterion)
    result = table.query.filter(*condition)

    if 'order_by' in ops_dict.keys():
        result = result.order_by(ops_dict['order_by'])

    if 'limit' in ops_dict.keys():
        result = result.limit(ops_dict['limit'])

    if 'page' in ops_dict.keys() and 'per_page' in ops_dict.keys():
        if 'limit' in ops_dict.keys():
            result = result.from_self()
        result = result.paginate(page=ops_dict['page'], per_page=ops_dict['per_page'])

    return result


def update_model(model, update):
    """
    已经获得实体对象的前提下使用这个方法
    :param model:
    :param update:
    :return:
    """
    def update_model(k,v,model):
        if not k.startswith("_"):
            model.__setattr__(k, v)

    if update is not None and len(update) > 0:
        list(map(lambda x: update_model(x,update[x],model), update))
    db.session.add(model)
    db.session.flush()
    # db.session.commit()   # autocommit为true
    return model

def update_table(table, update, **criterion):
    """
    更新指定的数据库表,可以更新一条或者多条数据
    取决于criterion能否帮助filter得到多条数据
    :param table:  数据库表隐射对象
    :param update: 要更新的字段
    :param criterion: 获取数据的条件
    :return: 更新的数据的条目数
    """
    update['gmt_modified'] = datetime.now()
    condition = list(map(lambda x: table.__dict__[x] == criterion[x], criterion))
    result = db.session.query(table).filter(*condition).update(update)
    db.session.flush()
    return result
